//! @author Adam Emil Skoog
//! @date   2012-01-05

#include "Game.h"
#include "Level.h"
#include "Mehdi.h"
#include "Block.h"
#include "House.h"
#include "Decoration.h"
#include "NPC.h"
#include "kedja/Component.h"
#include "kedja/EventManager.h"

namespace mehdi
 {
	void Game::run()
	 {
		sf::Event event;
		bool      running(true);

		kedja::Component::createMainComponent();

		imageLoader->add("gfx/mehdi.png","mehdi");
		imageLoader->add("gfx/bubble.png","bubble");
		imageLoader->add("gfx/dolan.png","dolan");
		imageLoader->add("gfx/topBar.png","topBar");
		imageLoader->add("gfx/letter.png","letter");
		imageLoader->add("gfx/block0.png","block0");
		imageLoader->add("gfx/inn.png","inn");
		imageLoader->add("gfx/interior0.png","interior0");
		imageLoader->add("gfx/signWelcome.png","signWelcome");
		imageLoader->loadAll();

		level = new Level;

		Decoration *const signWelcome(level->createObject<Decoration>());
		Image *const signWelcomeImage(imageLoader->get("signWelcome"));
		signWelcome->setImage(signWelcomeImage);
		signWelcome->position() = sf::Vector2f(40.f,Game::getWindow()->GetHeight() - 64.f - signWelcomeImage->getImage()->GetHeight());

		House *const house(level->createObject<House>());
		Image *const houseImage(imageLoader->get("inn"));
		house->setLevel(new Level);
		house->position() = sf::Vector2f(500.f,Game::getWindow()->GetHeight() - 64.f - houseImage->getImage()->GetHeight());
		house->setImage(houseImage);
		house->setCameraMovementEnabled(false);
		CollisionMask *const houseMask(house->createCollisionMask());
		houseMask->setSize(sf::Vector2f(110.f,138.f));
		houseMask->setPosition(sf::Vector2f(141.f,254.f));

		// Värdshus.
		House *const background(house->getLevel()->createObject<House>());
		 {
			background->setImage(Game::getImageLoader()->get("interior0"));
			background->setLevel(level);
			CollisionMask *const interior0Mask(background->createCollisionMask());
			interior0Mask->setSize(house->getCollisionMasks()[0]->getSize());
			interior0Mask->setPosition(sf::Vector2f(266.f,284.f));

			for (unsigned i(0); i < 10; ++ i)
			 {
				Block *const block(house->getLevel()->createObject<Block>());
				block->position() = sf::Vector2f(64.f * i,Game::getWindow()->GetHeight() - 64.f);
			 }

			NPC *const dolan(house->getLevel()->createObject<NPC>());
			dolan->setImage(imageLoader->get("dolan"));
			dolan->setName("Dolan");
			dolan->position() = sf::Vector2f(Game::getWindow()->GetWidth() - 140.f,Game::getWindow()->GetHeight() - 64 - dolan->getImage()->getImage()->GetHeight());
		 }

		for (unsigned i(0); i < 28; ++ i)
		 {
			Block *const block(level->createObject<Block>());
			block->position().y = Game::getWindow()->GetHeight() - 64.f;
			block->position().x = 64.f * i;
		 }

		Mehdi *const mehdi(level->createObject<Mehdi>());
		mehdi->position().x = 194.f;

		background->setMehdiSpawnPosition(sf::Vector2f(house->position().x + house->getCollisionMasks()[0]->getPosition().x,
		                                               Game::getWindow()->GetHeight() - 64.f -
													   Mehdi::getCurrentMehdi()->getCollisionMasks()[0]->getSize().y));
		house->setMehdiSpawnPosition(sf::Vector2f(background->getCollisionMasks()[0]->getPosition().x,
		                                          Game::getWindow()->GetHeight() - 64.f -
												  Mehdi::getCurrentMehdi()->getCollisionMasks()[0]->getSize().y));

		while (window->IsOpened())
		 {
			while (window->GetEvent(event))
			 {
				switch (event.Type)
				 {
					case sf::Event::Closed:
						window->Close();
						running = false;
						break;

					case sf::Event::Resized:
					case sf::Event::LostFocus:
					case sf::Event::GainedFocus:
					case sf::Event::TextEntered:
					case sf::Event::KeyPressed:
					case sf::Event::KeyReleased:
					case sf::Event::MouseWheelMoved:
					case sf::Event::MouseButtonPressed:
					case sf::Event::MouseButtonReleased:
					case sf::Event::MouseMoved:
					case sf::Event::MouseEntered:
					case sf::Event::MouseLeft:
					case sf::Event::JoyButtonPressed:
					case sf::Event::JoyButtonReleased:
					case sf::Event::JoyMoved:
					case sf::Event::Count:
						break;
				 }
			 }

			if (running)
			 {
				window->Clear(sf::Color(180,210,255));
				kedja::Component::getEventManager()->notifyMouseButtonIsDown(kedja::mouse::left,Game::getWindow()->GetInput().IsMouseButtonDown(sf::Mouse::Left));
				kedja::Component::getEventManager()->notifyMouseButtonIsDown(kedja::mouse::middle,Game::getWindow()->GetInput().IsMouseButtonDown(sf::Mouse::Middle));
				kedja::Component::getEventManager()->notifyMouseButtonIsDown(kedja::mouse::right,Game::getWindow()->GetInput().IsMouseButtonDown(sf::Mouse::Right));

				if (!isPaused())
					playtime += window->GetFrameTime();

				for (unsigned i(0); i < static_cast<unsigned>(sf::Key::Count); ++ i)
					kedja::Component::getEventManager()->notifyKeyIsDown(static_cast<sf::Key::Code>(i),Game::getWindow()->GetInput().IsKeyDown(static_cast<sf::Key::Code>(i)));

				// Allt ovan skall alltid vara först i bildrutan.

				level->update();

				// Detta skall alltid vara sist i bildrutan.
				kedja::Component::updateComponentSystem();
				window->Display();

				if (enterNewHouse)
				 {
					Level *const currentLevel(level);
					level         = oldLevel;
					oldLevel      = currentLevel;
					enterNewHouse = false;

					level->copyMehdi(Mehdi::getCurrentMehdi(),oldLevel);
					Mehdi::getCurrentMehdi()->position() = currentHouse->getMehdiSpawnPosition();
				 }
			 }
		 }

		clean();
	 }

	void Game::clean()
	 {
		kedja::Component::destroyMainComponent();

		if (oldLevel)
			delete oldLevel;

		if (level)
			delete level;

		delete imageLoader;
		delete window;
	 }

	sf::RenderWindow *const Game::getWindow()
	 {
		return window;
	 }

	ImageLoader *const Game::getImageLoader()
	 {
		return imageLoader;
	 }

	Level *const Game::getLevel()
	 {
		return level;
	 }

	void Game::setPaused(const bool &paused)
	 {
		Game::paused = paused;
	 }

	const bool &Game::isPaused()
	 {
		return paused;
	 }

	const double &Game::getPlaytime()
	 {
		return playtime;
	 }

	const double Game::getPlayFrameTime()
	 {
		if (!isPaused())
			return window->GetFrameTime();

		return .0;
	 }

	void Game::enterHouse(Level *const level,House *const house)
	 {
		oldLevel      = level;
		currentHouse  = house;
		enterNewHouse = true;
	 }

	sf::RenderWindow *const Game::window        = new sf::RenderWindow(sf::VideoMode(640,480),"Mehdi's quest for creditionals");
	ImageLoader      *const Game::imageLoader   = new ImageLoader;
	Level            *      Game::level         = NULL,
	                 *      Game::oldLevel      = NULL;
	House            *      Game::currentHouse  = NULL;
	bool                    Game::paused        = false,
	                        Game::enterNewHouse = false;
	double                  Game::playtime      = .0;
 }
